home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d7 / asycls10.arc / ASYNCH.CPP next >
C/C++ Source or Header  |  1991-04-28  |  14KB  |  399 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. //
  3. //  Asynchronous Class for C++
  4. //  Copyright (C) 1991 by Jui-Lin Hung and SPD!
  5. //
  6. //  You may freely use or incorporate these routines into your own programs
  7. //  without royalty to me, as I believe this is beneficial to programmers.
  8. //  However, I would like to request that if you distribute the source code,
  9. //  you would include this header in the source file and not remove it.
  10. //  Of course, I would have no way of knowing, but I am appealing to your
  11. //  sense of good will and morality.  Thank you, and I hope these routines
  12. //  are useful.
  13. //
  14. //  April, 1991 - Version 1.0
  15. //
  16. /////////////////////////////////////////////////////////////////////////////
  17.  
  18.  
  19. #include <dos.h>
  20.  
  21. #include "asynch.h"     // Asynch class definitions
  22.  
  23.  
  24. //-------------------------------------------------------------------------\\
  25.  
  26.  
  27. _asynch_info _ainfo;    // Global asynchronous info variable
  28.  
  29.  
  30. //-------------------------------------------------------------------------\\
  31.  
  32.  
  33. void far interrupt (*OldVect)(...);
  34.  
  35. void far interrupt asynch_irq(...)
  36. // Asynchronous port interrupt handler.  This is the new interrupt which
  37. // we will swap with the old one to handle all asynchronous i/o
  38. {
  39.     static int temp;
  40.  
  41.     enable();                               // enable interrupts
  42.     for (;;)
  43.     {
  44.         temp = inportb(_ainfo.base+IIR);    // why interrupt was called
  45.         if (temp & 0x01)                    // Nothing else to do
  46.         {
  47.             outportb(ICR,EOI);              // reset interrupt
  48.             return;                         // return to program
  49.         }
  50.         switch(temp)
  51.         {
  52.             case 0x00:  // modem status changed
  53.                 inportb(_ainfo.base+MSR);   // read in useless char
  54.                 break;
  55.             case 0x02:  // Request To Send char
  56.                 if (_ainfo.outhead != _ainfo.outtail)  // there's a char to send
  57.                 {
  58.                     // send the character
  59.                     outportb(_ainfo.base+TXR,_ainfo.outbuf[_ainfo.outhead++]);
  60.                     // if at end of buffer, reset pointer
  61.                     if (_ainfo.outhead == OBUF_LEN) _ainfo.outhead=0;
  62.                 }
  63.                 break;
  64.             case 0x04:  // character ready to be read in
  65.                 // read character into inbuffer
  66.                 _ainfo.inbuf[_ainfo.inhead++] = inportb(_ainfo.base+RXR);
  67.                 if (_ainfo.inhead == IBUF_LEN) // if at end of buffer
  68.                     _ainfo.inhead=0;           // reset pointer
  69.                 break;
  70.             case 0x06:  // line status has changed
  71.                 inportb(_ainfo.base+LSR);     // read in useless char
  72.                 break;
  73.         }
  74.     }
  75. }
  76.  
  77.  
  78. void Asynch::asynchInit()
  79. // Initializes variables, saves old interrupt vectors and sets the new
  80. // interrupts.  Initializes the asynchronous port too.
  81. {
  82.     _ainfo.inhead=_ainfo.intail=0;          // reset in buffer pointers
  83.     _ainfo.outhead=_ainfo.outtail=0;        // reset out buffer pointers
  84.     _ainfo.flow = 0;                        // Default flow control is off
  85.     _ainfo.nohangup = 0;                    // hangup when done
  86.  
  87.     OldVect = getvect(_ainfo.irq+MCI);      // Save old interrupt vector
  88.     setvect(_ainfo.irq+MCI,asynch_irq);     // Set up serial int handler
  89.     outportb(_ainfo.base+LCR, 0x03);        // Turn DTR and RTS on
  90.     disable();                              // disable ints during init
  91.     int temp = inportb(_ainfo.base+LSR);    // read serial port line status
  92.     temp = inportb(_ainfo.base+RXR);        // read char
  93.     temp = inportb(IMR);                    // get interrupt settings
  94.     temp = temp & ((IER<<_ainfo.irq)^0xff); // turn on serial interrupt
  95.     outportb(IMR, temp);                    // send out new int settings
  96.     outportb(_ainfo.base+IER, IER);         // turn on all IRQ events
  97.     outportb(_ainfo.base+MCR, inportb(_ainfo.base+MCR) | 0x0a);
  98.     enable();                               // re-enable all interrupts
  99. }
  100.  
  101.  
  102. Asynch::Asynch(unsigned char p)
  103. // Class constructor - set base address and irq number.
  104. {
  105.     switch(p)   // set up correct base address and irq for this port
  106.     {
  107.         case COM1:  // serial port 1
  108.             _ainfo.base = 0x03f8;   // base address for port 1
  109.             _ainfo.irq  = 4;        // interrupt number for port 1
  110.             break;
  111.         case COM2:  // serial port 2
  112.             _ainfo.base = 0x02f8;   // base address for port 2
  113.             _ainfo.irq  = 3;        // interrupt number for port 2
  114.             break;
  115.         case COM3:  // serial port 3
  116.             _ainfo.base = 0x03e8;   // base address for port 3
  117.             _ainfo.irq  = 4;        // interrupt number for port 3
  118.             break;
  119.         case COM4:  // serial port 4
  120.             _ainfo.base = 0x02e8;   // base address for port 4
  121.             _ainfo.irq  = 3;        // interrupt number for port 4
  122.             break;
  123.         default:  // defaults to com2
  124.             _ainfo.base = 0x02f8;   // base address for port 2
  125.             _ainfo.irq  = 3;        // interrupt number for port 2
  126.             break;
  127.     }
  128.  
  129.     _ainfo.baud = 2400;             // Default baud rate is 2400
  130.  
  131.     asynchInit();                   // call interrupt initialization
  132.     setBaud(_ainfo.baud);           // set to default baud rate
  133. }
  134.  
  135.  
  136. Asynch::Asynch(unsigned char p,unsigned int b)
  137. // Class constructor - set base address and irq number.
  138. // This particular constructor also sets the baud rate to the
  139. // specified speed
  140. {
  141.     switch(p)   // set up correct base address and irq for this port
  142.     {
  143.         case COM1:  // serial port 1
  144.             _ainfo.base = 0x03f8;   // base address for port 1
  145.             _ainfo.irq  = 4;        // interrupt number for port 1
  146.             break;
  147.         case COM2:  // serial port 2
  148.             _ainfo.base = 0x02f8;   // base address for port 2
  149.             _ainfo.irq  = 3;        // interrupt number for port 2
  150.             break;
  151.         case COM3:   // serial port 3
  152.             _ainfo.base = 0x03e8;   // base address for port 3
  153.             _ainfo.irq  = 4;        // interrupt number for port 3
  154.             break;
  155.         case COM4:  // serial port 4
  156.             _ainfo.base = 0x02e8;   // base address for port 4
  157.             _ainfo.irq  = 3;        // interrupt number for port 4
  158.             break;
  159.         default:    // defaults to com2
  160.             _ainfo.base = 0x02f8;   // base address for port 2
  161.             _ainfo.irq  = 3;        // interrupt number for port 2
  162.             break;
  163.     }
  164.  
  165.     _ainfo.baud = b;                // Default baud rate is 2400
  166.  
  167.     asynchInit();                   // call interrupt initialization
  168.     setBaud(_ainfo.baud);           // set to default baud rate
  169. }
  170.  
  171.  
  172.  
  173. Asynch::~Asynch()
  174. // Class destructor - de-initializes the asynchronous port, and restores
  175. // the old interrupts
  176. {
  177.     disable();                          // disable interrupts
  178.     int temp = inportb(IMR);
  179.     temp = temp | (IER << _ainfo.irq);
  180.     outportb(IMR, temp | CTS);
  181.     outportb(_ainfo.base+IIR, 0x00);
  182.     outportb(_ainfo.base+MCR, IER);
  183.     enable();                           // enable interrupts
  184.     setvect(_ainfo.irq+MCI,OldVect);    // reinstate old vector
  185. }
  186.  
  187.  
  188. void Asynch::setBaud(unsigned int b)
  189. // Sets the baud rate to the specified speed
  190. {
  191.     if (b > 49 && (long)b < 57601L)
  192.     {
  193.         float rate = 115200.0 / ((float)b);
  194.         _ainfo.baud = (unsigned int)rate;
  195.  
  196.         outportb(_ainfo.base+LCR, inportb(_ainfo.base+LCR) | 0x80);
  197.         outportb(_ainfo.base, (_ainfo.baud & 0x00ff));
  198.         outportb(_ainfo.base+IER, ((_ainfo.baud >> MCI) & 0x00ff));
  199.         outportb(_ainfo.base+LCR, inportb(_ainfo.base+LCR) & 0x7f);
  200.     }
  201. }
  202.  
  203.  
  204. int Asynch::dtr()
  205. // Returns 1 if the DTR is high, or if DTR remains low, returns a 0
  206. {
  207.     int addr;
  208.  
  209.     switch(_ainfo.port)
  210.     {
  211.         case COM1: addr = 0x03fe; break;
  212.         case COM2: addr = 0x02fe; break;
  213.         case COM3: addr = 0x03ee; break;
  214.         case COM4: addr = 0x02ee; break;
  215.     }
  216.     if (inportb(addr) & 128)
  217.         return(1);
  218.     delay(500);
  219.     return(inportb(addr) & 128);
  220. }
  221.  
  222.  
  223. void Asynch::setDtr()
  224. // This function basically sets the DTR to high.
  225. {
  226.     outportb(_ainfo.base+MCR, inportb(_ainfo.base+MCR) & 0x00fe);
  227. }
  228.  
  229.  
  230. void Asynch::dropDtr()
  231. // This function basically sets the DTR to low (i.e. hangs up the phone)
  232. {
  233.     int addr;
  234.  
  235.     if (!_ainfo.nohangup)
  236.     {
  237.         switch(_ainfo.port)
  238.         {
  239.             case COM1: addr = 0x03fc; break;
  240.             case COM2: addr = 0x02fc; break;
  241.             case COM3: addr = 0x03ec; break;
  242.             case COM4: addr = 0x02ec; break;
  243.         }
  244.         outportb(addr, inportb(addr) & 0xfe);
  245.         delay(500);
  246.     }
  247. }    
  248.  
  249.  
  250. int Asynch::inCount()
  251. // Counts how many characters are remaining to be read in from the input
  252. // buffer
  253. {
  254.     int len = _ainfo.intail - _ainfo.inhead;
  255.     return((len>0) ? len:(-len));
  256. }
  257.  
  258.  
  259. int Asynch::outCount()
  260. // Counts how many characters are remaining to be outputted in the output
  261. // buffer
  262. {
  263.     int len = _ainfo.outtail - _ainfo.outhead;
  264.     return((len>0) ? len:(-len));
  265. }
  266.  
  267.  
  268. void Asynch::flushInBuf()
  269. // Flushes the input buffer
  270. {
  271.     disable();                          // disable interrupts
  272.     _ainfo.inhead=_ainfo.intail=0;      // reset pointers (dump buffer)
  273.     enable();                           // enable interrupts
  274. }
  275.  
  276.  
  277. void Asynch::flushOutBuf()
  278. // Flushes the output buffer
  279. {
  280.     disable();                          // disable interrupts
  281.     _ainfo.outhead=_ainfo.outtail=0;    // reset pointers (dump buffer)
  282.     enable();                           // enable interrupts
  283. }
  284.  
  285.  
  286. Asynch &Asynch::operator<<(char ch)
  287. // Inserts the character to be outputted into the output buffer, checking
  288. // for an open slot in the output buffer array.  If there is, insert
  289. // the character, or if there isn't, wait until a slot opens up.
  290. {
  291.     if (ch)                         // If this is a valid char
  292.     {
  293.         enable();                   // turn on irqs to ensure data output
  294.  
  295.         // check buffer, and if full, wait for an available opening
  296.         while((_ainfo.outhead-1==_ainfo.outtail) ||
  297.               (_ainfo.outtail==OBUF_LEN-1 && _ainfo.outhead==0))
  298.             ;
  299.         disable();  // make sure nothing happens while changing buffer
  300.         _ainfo.outbuf[_ainfo.outtail++]=ch; // insert character into buffer;
  301.         if (_ainfo.outtail == OBUF_LEN)     // if at end of out buffer
  302.             _ainfo.outtail = 0;             // reset pointer
  303.         enable();                           // re-enable interrupts
  304.         outportb(_ainfo.base+DTR,0x0f);
  305.     }
  306.     return(*this);
  307. }
  308.  
  309.  
  310. Asynch &Asynch::operator<<(char *str)
  311. // Outputs a string to the serial port
  312. {
  313.     while (*str)
  314.     {
  315.         if (*str=='\n')
  316.             (*this) << '\r', (*this) << '\n';
  317.         else
  318.             (*this) << (*str);
  319.         str++;
  320.     }
  321.     return(*this);
  322. }
  323.  
  324.  
  325. Asynch &Asynch::operator>>(char &ch)
  326. // Returns either the character to be received from modem if there is one
  327. // waiting in the buffer, or returns a 0 if there is no character waiting.
  328. {
  329.     if (_ainfo.inhead != _ainfo.intail)     // there is a character
  330.     {
  331.         disable();                          // disable irqs while getting char
  332.         ch = _ainfo.inbuf[_ainfo.intail++]; // get character from buffer
  333.         if (_ainfo.intail == IBUF_LEN)      // if at end of in buffer
  334.             _ainfo.intail=0;                // reset pointer
  335.         enable();                           // re-enable interrupt
  336.         return(*this);                      // return the char
  337.     }
  338.     ch = 0;
  339.     return(*this);                          // return nothing
  340. }
  341.  
  342.  
  343. // C type functions for asynchronous i/o
  344. void Asynch::outCh(char ch)
  345. // Inserts the character to be outputted into output buffer.  If there is
  346. // an open slot in the output buffer array, insert character there, or
  347. // wait for a slot to open.
  348. {
  349.     if (ch)                         // If this is a valid char
  350.     {
  351.         enable();                   // turn on irqs to ensure data output
  352.  
  353.         // check buffer, and if full, wait for an available opening
  354.         while((_ainfo.outhead-1==_ainfo.outtail) ||
  355.               (_ainfo.outtail==OBUF_LEN-1 && _ainfo.outhead==0))
  356.             ;
  357.         disable();  // make sure nothing happens while changing buffer
  358.         _ainfo.outbuf[_ainfo.outtail++]=ch; // insert character into buffer;
  359.         if (_ainfo.outtail == OBUF_LEN)     // if at end of out buffer
  360.             _ainfo.outtail = 0;             // reset pointer
  361.         enable();                           // re-enable interrupts
  362.         outportb(_ainfo.base+DTR,0x0f);
  363.     }
  364. }
  365.  
  366.  
  367. void Asynch::outStr(char *str)
  368. // Outputs a string through the serial port
  369. {
  370.     while (*str)
  371.     {
  372.         if (*str=='\n')
  373.             outCh('\r'), outCh('\n');
  374.         else
  375.             outCh(*str);
  376.         str++;
  377.     }
  378. }
  379.  
  380.  
  381. char inCh()
  382. // Returns 0 if no character waiting, or the character itself if there
  383. // is a character waiting in the buffer
  384. {
  385.     if (_ainfo.inhead != _ainfo.intail)     // there is a character
  386.     {
  387.         disable();                          // disable irqs while getting char
  388.  
  389.         // get character from buffer
  390.         unsigned char ch = _ainfo.inbuf[_ainfo.intail++];
  391.  
  392.         if (_ainfo.intail == IBUF_LEN)      // if at end of in buffer
  393.             _ainfo.intail=0;                // reset pointer
  394.         enable();                           // re-enable interrupt
  395.         return(ch);                         // return the char
  396.     }
  397.     return(0);                              // return nothing
  398. }
  399.